package xml;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import ue.UE;
import Controller.Controller;
import eNodeB.Fabrique;

public class XMLDOMPARSER {

	private static XMLDOMPARSER singleton;
	private final DocumentBuilder builder;

	private XMLDOMPARSER() throws ParserConfigurationException, SAXException,
			SAXParseException {
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		builderFactory.setValidating(true);
		builderFactory.setNamespaceAware(true);
		builderFactory.setAttribute(
				"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
				"http://www.w3.org/2001/XMLSchema");
		builder = builderFactory.newDocumentBuilder();
		builder.setErrorHandler(Controller.getController());
	}

	public static XMLDOMPARSER getXMLDOMPARSER()
			throws ParserConfigurationException, SAXException,
			SAXParseException {
		if (singleton == null) {
			singleton = new XMLDOMPARSER();
		}
		return singleton;
	}

	public boolean parse(String file, String id) throws FileNotFoundException,
			SAXException, IOException, ParseXMLException, SAXParseException {

		Document document = builder.parse(new FileInputStream(file));

		Element rootElement = document.getDocumentElement();

		NodeList nodes = rootElement.getChildNodes();

		for (int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);

			if (node instanceof Element) {
				Element eTheMap = (Element) node;
				if (eTheMap.getAttributeNS(ConstanteParseur.NAMESPACE,
						ConstanteParseur.A_ID).equals(id)) {

					double x = Double.parseDouble(eTheMap.getAttributeNS(
							ConstanteParseur.NAMESPACE, ConstanteParseur.A_X));
					double y = Double.parseDouble(eTheMap.getAttributeNS(
							ConstanteParseur.NAMESPACE, ConstanteParseur.A_Y));
					String algorithm = eTheMap.getAttributeNS(
							ConstanteParseur.NAMESPACE,
							ConstanteParseur.A_ALGORITHM);
					Fabrique.getFabrique().createMap(id, x, y, algorithm);
					createENodeB(eTheMap);
					return true;
				}

			}
		}
		return false;

	}

	private void createENodeB(Element eSchedule) throws ParseXMLException {

		Element eEnodeB = (Element) eSchedule.getElementsByTagNameNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.E_ANTENNA).item(0);

		double x = getX(eEnodeB);
		double y = getY(eEnodeB);
		double coverage = Double.parseDouble(eEnodeB.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_COVERAGE));

		int nbRessourceBlocks = Integer.parseInt(eEnodeB
				.getAttributeNS(ConstanteParseur.NAMESPACE,
						ConstanteParseur.A_NBRESSOURCEBLOCK));

		String begin = eEnodeB.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_BEGIN);

		String end = eEnodeB.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_END);

		Fabrique.getFabrique().createEnodeB(nbRessourceBlocks, x, y, coverage,
				begin, end);

		NodeList users = eEnodeB.getElementsByTagNameNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.E_USER);
		for (int i = 0; i < users.getLength(); i++) {
			Node node = users.item(i);
			if (node instanceof Element) {
				Element user = (Element) node;
				createUser(user);

			}
		}

	}

	/**
	 * set CQI during a period for a user.
	 * 
	 * @param ue
	 *            The user.
	 * @param cqi
	 *            The cqi value.
	 * @throws ParseXMLException
	 */
	private void addCQI(UE ue, String cqi) throws ParseXMLException {
		int nbRB = Fabrique.getFabrique().getEnodeB().getMaxRessourceBlocks();
		String[] rbCQIValues = cqi.split(";");
		if (rbCQIValues.length != nbRB) {
			throw new ParseXMLException("problem string cqi");
		}

		for (int idRB = 0; idRB < nbRB; idRB++) {
			int cqiRB = Integer.parseInt(rbCQIValues[idRB]);
			if (cqiRB < 0 || cqiRB > 15) {
				throw new ParseXMLException("bad value cqi for rb " + idRB
						+ "for UE:" + ue.getId());
			}
			ue.addCqi(idRB, cqiRB);
		}

	}

	private void addThroughput(UE ue, String throughput)
			throws ParseXMLException {
		int nbRB = Fabrique.getFabrique().getEnodeB().getMaxRessourceBlocks();
		String[] rbThroughputValues = throughput.split(";");
		if (rbThroughputValues.length != nbRB) {
			throw new ParseXMLException("problem string throughput");
		}

		for (int idRB = 0; idRB < nbRB; ++idRB) {
			ue.addThroughput(idRB, Double.parseDouble(rbThroughputValues[idRB]));
		}
	}

	private void createUser(Element eUser) throws ParseXMLException {
		String id = eUser.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_ID);
		double x = getX(eUser);
		double y = getY(eUser);
		String begin = eUser.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_BEGIN);
		String end = eUser.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_END);
		String cqi = eUser.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_CQI);
		String throughput = eUser.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_THROUGHPUT);
		int r = Integer.parseInt(eUser.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_RED));
		int g = Integer.parseInt(eUser.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_GREEN));
		int b = Integer.parseInt(eUser.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_BLUE));
		UE ue = Fabrique.getFabrique().createUser(id, x, y, begin, end);

		addCQI(ue, cqi);
		addThroughput(ue, throughput);
		// if (ColorExist.addInList(r + ";" + g + ";" + b)) {
		// throw new ParseXMLException("color already exists id" + ue.getId()
		// + " with color r= " + r + " g= " + g + " b= " + b);
		// } else {
		ue.setColor(r, g, b);
		// }

		NodeList datas = eUser.getElementsByTagNameNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.E_DATA);
		for (int i = 0; i < datas.getLength(); i++) {
			Node node = datas.item(i);
			if (node instanceof Element) {
				Element data = (Element) node;
				createData(data, ue);

			}
		}

	}

	private void createData(Element data, UE ue) throws ParseXMLException {

		String begin = data.getAttributeNS(ConstanteParseur.NAMESPACE,
				ConstanteParseur.A_BEGIN);
		String hexDatas = data.getTextContent();
		Fabrique.getFabrique().createData(begin, hexDatas, ue);
	}

	private double getX(Element element) throws ParseXMLException {
		double x = Double.parseDouble(element.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_XPOSITION));
		if (x > Fabrique.getFabrique().getTheMap().getX()) {
			ParseXMLException.greatherThanMaxAttributeX(
					element.getNamespaceURI(), ConstanteParseur.A_XPOSITION, x);
		}
		return x;
	}

	private double getY(Element element) throws ParseXMLException {
		double y = Double.parseDouble(element.getAttributeNS(
				ConstanteParseur.NAMESPACE, ConstanteParseur.A_YPOSITION));
		if (y > Fabrique.getFabrique().getTheMap().getX()) {
			ParseXMLException.greatherThanMaxAttributeY(
					element.getNamespaceURI(), ConstanteParseur.A_YPOSITION, y);
		}
		return y;
	}
}
